/**
 * FrequenceUtils.java
 * com.sftz.framework.util
 * Copyright (c) 2017, 北京科技有限公司版权所有.
*/

package com.sftz.framework.util;

import java.util.Map;

import org.apache.commons.lang.time.StopWatch;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import com.google.common.collect.Maps;
import com.uxuexi.core.common.util.Util;

/**
 * HttpSession请求频率限制工具
 * <p>
 * 将Map替换为ThreadLocal<FrequenceUnit>即成为按照线程统计的工具
 * @author   朱晓川
 * @Date	 2017年11月28日 	 
 */
public class SessionReqLimitUtils {

	private static final Log log = Logs.get();

	private static Map<String, FrequenceUnit> sessionLocal = Maps.newConcurrentMap();

	/** 
	* <p> 
	* Limit call count in split time 
	* </p> 
	*  通过达到指定次数所花的时间是否超过给定时间来判断频率是否超标，每统计一次就重置次数和秒表
	* @param limitSplitTime  限制时间  单位(毫秒)
	* @param limitCount      限制次数  单位(次)
	* @throws InterruptedException 
	*/
	public static boolean limit(final long limitSplitTime, final int limitCount, String sessionId) {
		boolean result = false;
		FrequenceUnit funit = sessionLocal.get(sessionId);
		if (Util.isEmpty(funit)) {
			funit = new FrequenceUnit();
			funit.limitSplitTime = limitSplitTime;
			funit.limitCount = limitCount;
			sessionLocal.put(sessionId, funit);
			funit.watch.start();
		}

		/*
		 * 当累计次数超过限制次数的时候，计算时间间隔,
		 * 如果时间间隔小于给定的限制，则说明请求过于频繁
		 */
		if (funit.realCount >= funit.limitCount) {
			funit.watch.split();//掐表，计算时间间隔
			long diffTime = funit.watch.getSplitTime();

			log.debug("sessionId:" + sessionId + ",间隔时间:" + diffTime);

			if (diffTime <= funit.limitSplitTime) {
				result = true;
			}

			/*
			 * 重置秒表
			 */
			funit.realCount = 0;
			//reset + start
			funit.watch.reset();
			funit.watch.start();
		}

		funit.realCount++;
		return result;
	}

	/** 
	 * FrequenceUnit 
	 */
	private static class FrequenceUnit {
		FrequenceUnit() {
			this.watch = new StopWatch();
		}

		long limitSplitTime;
		int limitCount;
		StopWatch watch;
		int realCount = 0;
	}

}
